<?php

namespace Xin\Pipeline;

use Xin\Pipeline\Contracts\Repository;

class PipeRepository implements Repository
{
	/**
	 * @var array
	 */
	protected $stages = [];

	/**
	 * 初始化场景器
	 * @param string $name
	 * @return void
	 */
	protected function init($name)
	{
		if (!isset($this->stages[$name])) {
			$this->stages[$name] = [];
		}
	}

	/**
	 * 获取所有的场景器
	 * @return array
	 */
	public function all()
	{
		return $this->stages;
	}

	/**
	 * 获取场景器
	 * @param string $name
	 * @return array
	 */
	public function get($name = 'global')
	{
		return $this->stages[$name] ?? [];
	}

	/**
	 * 添加场景器
	 * @param callable $handler
	 * @param string $name
	 * @return $this
	 */
	public function push(callable $handler, $name = 'global')
	{
		$this->init($name);

		$this->stages[$name][] = $handler;

		return $this;
	}

	/**
	 * 添加一组中间件
	 * @param callable[] $handlers
	 * @param string $name
	 * @return $this
	 */
	public function pushMany(array $handlers, $name = 'global')
	{
		foreach ($handlers as $handler) {
			$this->push($handler, $name);
		}

		return $this;
	}

	/**
	 * 指定位置插入场景器
	 * @param callable $handler
	 * @param int $index
	 * @param string $name
	 * @return $this
	 */
	public function insert(callable $handler, $index = 0, $name = 'global')
	{
		$this->init($name);

		array_splice($this->stages[$name], $index, 0, [$handler]);

		return $this;
	}

	/**
	 * 指定位置插入一组场景器
	 * @param string $name
	 * @param callable[] $handlers
	 * @param int $index
	 * @return $this
	 */
	public function insertMany(array $handlers, $index = 0, $name = 'global')
	{
		$this->init($name);

		array_splice($this->stages[$name], $index, 0, [$handlers]);

		return $this;
	}

	/**
	 * 移除场景器
	 * @param callable $handler
	 * @param string $name
	 * @return $this
	 */
	public function remove($handler, $name = 'global')
	{
		if (!isset($this->stages[$name])) {
			return $this;
		}

		$stages = &$this->stages[$name];
		if (($index = array_search($handler, $stages)) !== false) {
			unset($stages[$index]);
		}
		unset($stages);

		return $this;
	}

	/**
	 * 清除场景器
	 * @param string $name
	 * @return $this
	 */
	public function clear($name = 'global')
	{
		if ($name) {
			if (isset($this->stages[$name])) {
				$this->stages[$name] = [];
			}
		} else {
			$this->stages = [];
		}

		return $this;
	}
}
